package com.divillysausages.dsair.windows 
{
	import com.bit101.components.PushButton;
	import com.bit101.components.Style;
	import com.divillysausages.dsair.DSAir;
	import flash.display.NativeWindow;
	import flash.display.NativeWindowInitOptions;
	import flash.display.NativeWindowType;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFormat;
	
	/**
	 * An alert window that we can use to show a status
	 * @author Damian Connolly
	 */
	public class Alert
	{
		
		/********************************************************************/
		
		private static var m_options:NativeWindowInitOptions 	= null; // the options for the alert window
		private static var m_format:TextFormat					= null;	// the textformat for our text
		
		/********************************************************************/
		
		/**
		 * Should the alert be destroyed when we close it? The default is true
		 */
		public var destroyOnClose:Boolean = true;
		
		/********************************************************************/
		
		protected var m_window:NativeWindow 		= null; // the window we're going to show
		protected var m_msg:TextField				= null; // the text object for our msg
		protected var m_padding:Number				= 20.0; // the paddding for the text etc
		protected var m_buttons:Vector.<PushButton>	= null; // the buttons for this window
		protected var m_callbacks:Vector.<Function>	= null; // the callbacks for our buttons
		
		/********************************************************************/
		
		/**
		 * Can this alert be used? Alerts can't be used if they've been closed via the "x" button
		 */
		public function get canBeUsed():Boolean { return !this.m_window.closed; }
		
		/**
		 * Sets the title of the window
		 */
		public function set title( s:String ):void
		{
			if( this.canBeUsed )
				this.m_window.title = s;
			else
				DSAir.warn( this, "Can't use the alert as the window has been closed - need to create a new one" );
		}
		
		/**
		 * Sets the message for the window
		 */
		public function set msg( s:String ):void
		{
			this.m_msg.text 	= s;
			this.m_msg.height	= this.m_msg.textHeight + 4.0;
			
			// if there's buttons, resize them
			if ( this.m_buttons != null )
			{
				for each( var btn:PushButton in this.m_buttons )
					btn.y = this.m_msg.y + this.m_msg.height + this.m_padding;
			}
			
			// resize the window
			this._resizeWindow();
		}
		
		/********************************************************************/
		
		/**
		 * Creates a new Alert window
		 * @param title The title of the new window
		 * @param msg The message to show
		 */
		public function Alert( title:String, msg:String ) 
		{
			// create the window options if needed
			if ( Alert.m_options == null )
			{
				Alert.m_options 				= new NativeWindowInitOptions;
				Alert.m_options.maximizable		= false;
				Alert.m_options.minimizable		= false;
				Alert.m_options.resizable		= false;
				Alert.m_options.type			= NativeWindowType.UTILITY;
			}
			
			// create our format if needed
			if ( Alert.m_format == null )
				Alert.m_format = new TextFormat( Style.fontName, Style.fontSize, Style.LABEL_TEXT );
			
			// create the window
			this.m_window = WindowManager.instance.createWindow( Alert.m_options, title, 0.0, 0.0, 0.0, 0.0, false, false );
			
			// create our text
			this.m_msg						= new TextField;
			this.m_msg.defaultTextFormat	= Alert.m_format;
			this.m_msg.multiline			= true;
			this.m_msg.wordWrap				= true;
			this.m_msg.htmlText				= msg;
			this.m_msg.width				= this.m_window.stage.stageWidth - this.m_padding * 2.0;
			this.m_msg.height				= this.m_msg.textHeight + 4.0;
			this.m_msg.selectable			= false;
			this.m_msg.mouseEnabled			= false;
			this.m_msg.x					= this.m_padding;
			this.m_msg.y					= this.m_padding;
			this.m_window.stage.addChild( this.m_msg );
			
			// create our vectors
			this.m_buttons 		= new Vector.<PushButton>;
			this.m_callbacks	= new Vector.<Function>;
			
			// resize the alert
			this._resizeWindow();
		}
		
		/**
		 * Destroys the alert window and clears it for garbage collection
		 */
		public function destroy():void
		{
			// remove our text
			this.m_msg.parent.removeChild( this.m_msg );
			
			// kill our buttons
			for each( var btn:PushButton in this.m_buttons )
				btn.destroy();
				
			// clear our vectors
			this.m_buttons.length 	= 0;
			this.m_callbacks.length	= 0;
			
			// close our window
			if( !this.m_window.closed )
				this.m_window.close();
			
			// null our props
			this.m_window		= null;
			this.m_msg 			= null;
			this.m_buttons		= null;
			this.m_callbacks	= null;
		}
		
		/**
		 * Adds a button to the window
		 * @param label The label for the button
		 * @param onClick The function to call when we click on the button
		 * @param enabled Is the button enabled?
		 * @return The PushButton created, or null if the alert can't be used
		 */
		public function addButton( label:String, onClick:Function = null, enabled:Boolean = true ):PushButton
		{
			// make sure the alert can be used
			if ( !this.canBeUsed )
			{
				DSAir.warn( this, "Can't add a button to the alert as the window has been closed - need to create a new one" );
				return null;
			}
			
			// adds the button
			var btn:PushButton	= new PushButton( this.m_window.stage, 0.0, 0.0, label, this._onClick );
			btn.x				= this.m_window.stage.stageWidth - btn.width - this.m_padding;
			btn.y				= this.m_msg.y + this.m_msg.height + this.m_padding;
			
			// enabled/disable the button
			btn.enabled = enabled;
			
			// gets how many buttons are there previously
			if ( this.m_buttons.length > 0 )
				btn.x -= this.m_buttons.length * btn.width + this.m_buttons.length * this.m_padding * 0.5;
			
			// add it 
			this.m_buttons.push( btn );
			
			// hold our callback
			if ( onClick != null && onClick.length != 0 )
			{
				DSAir.error( this, "The onClick callback doesn't take any parameters" );
				onClick = null;
			}
			
			// add it
			this.m_callbacks.push( onClick );
				
			// resize the alert window
			if ( btn.x < this.m_padding )
			{
				var diffX:Number				= this.m_padding - btn.x;
				this.m_window.stage.stageWidth += diffX;
				for each( var b:PushButton in this.m_buttons )
					b.x += diffX;
			}
			this._resizeWindow();
			
			// return the button
			return btn;
		}
		
		/**
		 * Shows the window
		 */
		public function show():void
		{
			// make sure that the window can be used
			if( !this.canBeUsed )
				return DSAir.warn( this, "Can't show the alert as the window has been closed - need to create a new one" );
				
			// center and show
			WindowManager.instance.centerWindowOnApp( this.m_window );
			this.m_window.activate();
		}
		
		/**
		 * Hides the alert and destroys it
		 */
		public function hide():void
		{
			// make sure that the window can be used
			if ( !this.canBeUsed )
				return DSAir.warn( this, "Can't close the alert as the window has been closed - need to create a new one" );
				
			if ( this.destroyOnClose )
				this.destroy(); 
			else
			{
				this.m_window.visible = false;
				WindowManager.instance.giveRootWindowFocus(); // give the root window focus as this window still has it
			}
		}
		
		/********************************************************************/
		
		/**
		 * Resizes the window so the text and buttons all fit properly
		 */
		protected function _resizeWindow():void
		{
			// make sure the alert can be used
			if( !this.canBeUsed )
				return DSAir.warn( this, "Can't resize the alert as the window has been closed - need to create a new one" );
				
			// resize our text
			this.m_msg.width 	= this.m_window.stage.stageWidth - this.m_padding * 2.0;
			this.m_msg.height	= this.m_msg.textHeight + 4.0;
			
			// move our buttons
			for each( var btn:PushButton in this.m_buttons )
				btn.y = this.m_msg.y + this.m_msg.height + this.m_padding;
				
			// resize our height
			if ( this.m_buttons.length > 0 )
			{
				btn				 				= this.m_buttons[this.m_buttons.length - 1];
				this.m_window.stage.stageHeight = btn.y + btn.height + this.m_padding;
			}
			else
				this.m_window.stage.stageHeight	= this.m_msg.y + this.m_msg.height + this.m_padding;
		}
				
		/********************************************************************/
		
		// called when we click one of the buttons
		private function _onClick( e:MouseEvent ):void
		{
			// get our callback
			var callback:Function	= null;
			var index:int 			= this.m_buttons.indexOf( e.target );
			if ( index >= 0 && index <= this.m_callbacks.length )
				callback = this.m_callbacks[index];
				
			// call it
			if ( callback != null )
				callback();
				
			// hide the alert
			this.hide();
		}
		
	}

}